home *** CD-ROM | disk | FTP | other *** search
/ T&A 2 the Maxx 3 / T and A 2 The Maxx Number 3.iso / viewers / unixview / xflitar.z / xflitar / xflick.c < prev    next >
C/C++ Source or Header  |  1991-04-19  |  16KB  |  656 lines

  1. /*
  2.                xflick - Ron Schnell, March, 1991
  3.  
  4.            This code is provided as is, with no warrantees, expressed
  5.                or implied.  I believe this code to be free of encumbrance,
  6.            and offer it to the public domain.  I ask, however, that
  7.            this paragraph and my name be retained in any modified
  8.            versions of the file you may make, and that you notify me
  9.            of any improvements you make to the code.
  10.  
  11.            Ron Schnell (ronnie@sos.com)
  12.  
  13. */
  14.  
  15. /*
  16.     The following changes are from Michael Pall
  17.     (pall@rz.uni-karlsruhe.de) Mar 25-28 1991:
  18.  
  19.     Lots of bugfixes and changes to the structure of the files.
  20.     The file is interpreted before we display it.
  21.     Moved the interpretation part to read.c.
  22.     We use Pixmaps and/or XImages.
  23.     Added interactive input to change the speed/single step.
  24. */
  25.  
  26. #include <stdio.h>
  27. #include <sys/types.h>
  28. #include <sys/signal.h>
  29. #include <sys/time.h>
  30. #include "xflick.h"
  31. #include <X11/Xos.h>
  32. #include <X11/Xlib.h>
  33. #include <X11/Xutil.h>
  34. #include <X11/Xatom.h>
  35.  
  36.  
  37. int verbose = 0;
  38.  
  39. static int timeout;        /* Necessary global for itimer waiting */
  40. static int usecs,rsecs;        /* ditto */
  41.  
  42. static Display *display;    /* The display connection */
  43. static int screen;        /* The default screen */
  44. static Window rootw, window;    /* Root window and our own window */
  45. static XImage *img;        /* The image for the current frame */
  46. static GC gc, blackgc;        /* Graphics contexts */
  47. static Colormap cmap;        /* The colormap for our window */
  48. static XEvent event;        /* Events for our window */
  49.  
  50. static flag_img = 0;        /* Use XImages instead of Pixmaps */
  51. static flag_noint = 0;        /* Don't interpret file first */
  52.  
  53. static int fdelay;        /* Frame delay */
  54. static int wwidth, wheight;    /* Width and height of the window */
  55.  
  56. /* The structure to hold the elements of the interpreted display list */
  57.  
  58. struct disp_list
  59. {
  60.     int disp_type;
  61.     int disp_frame;
  62.     Pixmap disp_pix;
  63.     XImage *disp_img;
  64.     XColor *disp_cols;
  65.     int disp_numcol;
  66.     int disp_width, disp_height;
  67.     int disp_destx, disp_desty;
  68.     struct disp_list *disp_next;
  69. };
  70.  
  71. static struct disp_list disp_root;    /* The start of the display list */
  72. static struct disp_list *disp_cur;    /* The current position */
  73.  
  74. extern void interpret_fli();
  75.  
  76. /* Function which gets called by the signal handler when SIGALRM
  77.    occurs */
  78.  
  79. static
  80. bong()
  81. {
  82.     timeout = True;
  83. }
  84.  
  85.  
  86. /* Convert the frame delay to microseconds/seconds */
  87.  
  88. static void
  89. convert_fdelay()
  90. {
  91.     usecs = (fdelay % 70) * 14285;
  92.     rsecs = fdelay / 70;
  93. }
  94.  
  95. /* Print an error message and exit */
  96.  
  97. void
  98. xferror(str)
  99. char *str;
  100. {
  101.     (void) fprintf(stderr, "%s\n", str);
  102.     exit(-1);
  103. }
  104.  
  105. /* Print a usage message and exit */
  106.  
  107. static void
  108. usage()
  109. {
  110.     (void) fprintf(stderr,
  111.     "Usage: xflick [-v] [-r<count>] [-d<delay>] [-i] [-n] file\n");
  112.     (void) fprintf(stderr, " -v Verbose Debugging info\n\
  113. -r<count>  Repeat count times\n\
  114.  -d<delay>  Delay between frames in 1/70s\n\
  115.  -i         Use XImages instead of Pixmaps (slower but some servers need it)\n\
  116.  -n         Don't interpret file before display \
  117. (slower but uses less memory)\n");
  118.     exit(0);
  119. }
  120.  
  121. /* Check for pending KeyPress events and process them */
  122.  
  123. static void
  124. check_key()
  125. {
  126.     static int stepflag = 0;    /* Default: singlestep is off */
  127.  
  128.     char kbuf;            /* The buffer to hold the translation */
  129.     int onestep = stepflag;    /* 1 if we should loop waiting for a step */
  130.  
  131.     /* We poll the event Queue and block only in singlestep mode */
  132.  
  133.     while (onestep || QLength(display) > 0)
  134.     {
  135.     /* Get the event (blocks until event received) */
  136.  
  137.     XNextEvent(display, &event);
  138.  
  139.     /* Is it a KeyPress event and is it for our window (just in case)? */
  140.  
  141.     if (event.type == KeyPress && ((XKeyEvent *)&event)->window == window)
  142.     {
  143.         /* Translate the event to a string */
  144.         if (XLookupString((XKeyEvent *)&event, &kbuf, 1, NULL, NULL) != 1)
  145.         continue;
  146.  
  147.         /* Uppercase to lowercase mapping. We don't use ctype.h since
  148.            it's only used here  */
  149.  
  150.         if (kbuf>='A' && kbuf<='Z')
  151.         kbuf += 0x20;
  152.  
  153.         switch (kbuf)
  154.         {
  155.         /* Minus: Slow down */
  156.         case '-':
  157.         fdelay++;
  158.         convert_fdelay();
  159.         break;
  160.         /* Plus: Speed up */
  161.         case '+':
  162.         if (fdelay)
  163.             fdelay--;
  164.         convert_fdelay();
  165.         break;
  166.         /* Space: Single step */
  167.         case ' ':
  168.         stepflag = 1;
  169.         onestep = 0;
  170.         break;
  171.         /* Return: Continue animation */
  172.         case 0x0d:
  173.         stepflag = 0;
  174.         onestep = 0;
  175.         break;
  176.         /* 'q': Quit */
  177.         case 'q':
  178.         exit(0);
  179.         break;
  180.         }
  181.     }
  182.     }
  183. }
  184.  
  185.  
  186. /* Function to display the interpretation immediately */
  187.  
  188. static void
  189. func_disp(ftype, frame, buf, srcx, srcy, destx, desty, swidth, sheight)
  190. int ftype;
  191. int frame;
  192. unsigned char *buf;
  193. int srcx, srcy;
  194. int destx, desty;
  195. int swidth, sheight;
  196. {
  197.     static int colchange=0;        /* Colormap has changed */
  198.  
  199.     struct itimerval iclock;        /* For timeout setting */
  200.     XColor color;
  201.  
  202.     switch (ftype) {
  203.     case FLI_COPY:
  204.     case FLI_LC:
  205.     case FLI_BRUN:
  206.     img->data = (char *)buf;
  207.     XPutImage(display, window, gc, img, srcx, srcy, destx, desty,
  208.           swidth, sheight);
  209.     break;
  210.     case FLI_BLACK:
  211.     XFillRectangle(display, window, blackgc, destx, desty,
  212.                swidth, sheight);
  213.     break;
  214.     case FLI_COLOR:
  215.     while(srcy--)
  216.     {
  217.         color.red = ((*(buf++) & 0x3f) << 2) << 8;
  218.         color.green = ((*(buf++) & 0x3f) << 2) << 8;
  219.         color.blue = ((*(buf++) & 0x3f) << 2) << 8;
  220.         color.pixel = srcx++;
  221.         color.flags = DoRed|DoGreen|DoBlue;
  222.         XStoreColor(display, cmap, &color);
  223.     }
  224.     colchange = 1;
  225.     break;
  226.     case FLI_SYNC:
  227.     if (colchange)
  228.     {
  229.         XSetWindowColormap(display, window, cmap);
  230.         colchange = 0;
  231.     }
  232.     XSync(display, 0);
  233.  
  234.     check_key();
  235.  
  236.     /* Do we have a delay between the frames? */
  237.     if (usecs || rsecs)
  238.     {
  239.         timeout = False;
  240.         signal(SIGALRM, bong);
  241.         iclock.it_value.tv_sec = rsecs;
  242.         iclock.it_value.tv_usec = usecs;
  243.         iclock.it_interval.tv_sec = rsecs;
  244.         iclock.it_interval.tv_usec = usecs;
  245.         (void) setitimer(0, &iclock, 0);
  246.         
  247.         if (!timeout)
  248.         (void) pause();
  249.         
  250.         iclock.it_value.tv_sec = 0;
  251.         iclock.it_value.tv_usec = 0;
  252.         iclock.it_interval.tv_sec = 0;
  253.         iclock.it_interval.tv_usec = 0;
  254.         (void) setitimer(0, &iclock, 0);
  255.     }
  256.     break;
  257.     }
  258.  
  259. }
  260.  
  261. /* Store the interpretation */
  262.  
  263. static void
  264. func_interp(ftype, frame, buf, srcx, srcy, destx, desty, swidth, sheight)
  265. int ftype;        /* The type of this chunk */
  266. int frame;        /* The number of this frame */
  267. unsigned char *buf;    /* A pointer to the pixel/colormap data */
  268. int srcx, srcy;        /* The upper left corner in the data array */
  269. int destx, desty;    /* The upper left corner in the window */
  270. int swidth, sheight;    /* The dimensions of the rectangle */
  271. {
  272.     XColor *coltmp;    /* Temporary storage for pointer to XColor struct */
  273.     Pixmap pixtmp;    /* Temporary storage for the Pixmap id */
  274.  
  275.     /* Allocate another element in the display list */
  276.     disp_cur->disp_next = (struct disp_list *)malloc(sizeof(struct disp_list));
  277.     disp_cur = disp_cur->disp_next;
  278.  
  279.     /* Clear the pointer to the next element so we find the end of the list */
  280.     disp_cur->disp_next = (struct disp_list *)0;
  281.  
  282.     /* Copy info pertaining to all or most of the chunks */
  283.     disp_cur->disp_type = ftype;
  284.     disp_cur->disp_frame = frame;
  285.     disp_cur->disp_width = swidth;
  286.     disp_cur->disp_height = sheight;
  287.     disp_cur->disp_destx = destx;
  288.     disp_cur->disp_desty = desty;
  289.  
  290.     switch (ftype) {
  291.     case FLI_COPY:
  292.     case FLI_LC:
  293.     case FLI_BRUN:
  294.     img->data = (char *)buf;
  295.  
  296.     /* There's no reason to store the first frame in a Pixmap since it
  297.        will be used only once. Also use XImages if we've been told so */
  298.     if (frame==0 || flag_img)
  299.     {
  300.         disp_cur->disp_pix = (Pixmap)0;    /* No Pixmap */
  301.         disp_cur->disp_img = XSubImage(img, srcx, srcy, swidth, sheight);
  302.     }
  303.     else
  304.     /* Otherwise we create a Pixmap and copy the changed rectangle to it */
  305.     {
  306.         pixtmp = XCreatePixmap(display, rootw, swidth, sheight, 8);
  307.         if (!pixtmp)
  308.         xferror("Cannot create Pixmap. Try command line switch -i.");
  309.  
  310.         XPutImage(display, pixtmp, gc, img, srcx, srcy, 0, 0,
  311.               swidth, sheight);
  312.         disp_cur->disp_pix = pixtmp;
  313.     }
  314.     break;
  315.     case FLI_COLOR:
  316.     /* Create an array of XColor to hold the colors. Specific to FLI_COLOR:
  317.        srcx is the starting color index and srcy is the number of colors */
  318.     coltmp =  (XColor *)malloc(srcy * sizeof(XColor));
  319.     disp_cur->disp_cols = coltmp;
  320.     disp_cur->disp_numcol = srcy;
  321.  
  322.     /* Copy the changed colors to the XColor array */
  323.     while(srcy--)
  324.     {
  325.         coltmp->red = ((*(buf++) & 0x3f) << 2) << 8;
  326.         coltmp->green = ((*(buf++) & 0x3f) << 2) << 8;
  327.         coltmp->blue = ((*(buf++) & 0x3f) << 2) << 8;
  328.         coltmp->pixel = srcx++;
  329.         coltmp->flags = DoRed|DoGreen|DoBlue;
  330.         coltmp++;
  331.     }
  332.     break;
  333.  
  334.     /* FLI_BLACK and FLI_SYNC only need to be stored */
  335.     case FLI_BLACK:
  336.     case FLI_SYNC:
  337.     break;
  338.     }
  339.  
  340. }
  341.  
  342. /* Display the stored interpretation */
  343.  
  344. static void
  345. display_interp(dc)
  346. struct disp_list *dc;    /* The structure holding the info on the chunk */
  347. {
  348.     static int colchange=0;    /* Colormap has changed */
  349.  
  350.     struct itimerval iclock;    /* For timeout setting */
  351.     int swidth, sheight;    /* Dimension of the changing rectangle */
  352.     int destx, desty;        /* Upper left corner of the rectangle */
  353.  
  354.     /* Copy some fields from the structure */
  355.     swidth = dc->disp_width;
  356.     sheight = dc->disp_height;
  357.     destx = dc->disp_destx;
  358.     desty = dc->disp_desty;
  359.  
  360.     switch (dc->disp_type) {
  361.     case FLI_COPY:
  362.     case FLI_LC:
  363.     case FLI_BRUN:
  364.     /* A Pixmap needs to be copied internally by the server */
  365.     if (dc->disp_pix)
  366.     {
  367.         XCopyArea(display, dc->disp_pix, window, gc, 0, 0,
  368.               swidth, sheight, destx, desty);
  369.     }
  370.     else
  371.     /* XImages need to be transferred from the client */
  372.     {
  373.         XPutImage(display, window, gc, dc->disp_img, 0, 0, destx, desty,
  374.               swidth, sheight);
  375.     }
  376.     break;
  377.     case FLI_BLACK:
  378.     /* Clear the whole rectangle */
  379.     XFillRectangle(display, window, blackgc, destx, desty,
  380.                swidth, sheight);
  381.     break;
  382.     case FLI_COLOR:
  383.     /* Store the changed colors in the colormap and note that */
  384.     XStoreColors(display, cmap, dc->disp_cols, dc->disp_numcol);
  385.     colchange = 1;
  386.     break;
  387.     case FLI_SYNC:
  388.     /* If the colors have changed we set the colormap for the window */
  389.     if (colchange)
  390.     {
  391.         XSetWindowColormap(display, window, cmap);
  392.         colchange = 0;
  393.     }
  394.     /* Keep things in sync */
  395.     XSync(display, False);
  396.  
  397.     check_key();
  398.  
  399.     /* Do we have a delay between the frames? */
  400.     if (usecs || rsecs)
  401.     {
  402.         timeout = False;
  403.         signal(SIGALRM, bong);
  404.         iclock.it_value.tv_sec = rsecs;
  405.         iclock.it_value.tv_usec = usecs;
  406.         iclock.it_interval.tv_sec = rsecs;
  407.         iclock.it_interval.tv_usec = usecs;
  408.         (void) setitimer(0, &iclock, 0);
  409.         
  410.         if (!timeout)
  411.         (void) pause();
  412.         
  413.         iclock.it_value.tv_sec = 0;
  414.         iclock.it_value.tv_usec = 0;
  415.         iclock.it_interval.tv_sec = 0;
  416.         iclock.it_interval.tv_usec = 0;
  417.         (void) setitimer(0, &iclock, 0);
  418.     }
  419.     break;
  420.     }
  421. }
  422.  
  423.  
  424. /* Draw a given string to the center of the window */
  425.  
  426. static void
  427. text_center(str)
  428. char *str;
  429. {
  430.     XFontStruct *fixedfont;
  431.     GC fontgc;
  432.     int w;
  433.  
  434.     /* Load the fixed width font */
  435.  
  436.     fixedfont = XLoadQueryFont(display, "fixed");
  437.     if (fixedfont)
  438.     {
  439.     /* Create a GC to draw the font */
  440.  
  441.     fontgc = XCreateGC(display, rootw, 0, NULL);
  442.     XCopyGC(display, gc, -1, fontgc);
  443.     XSetBackground(display, fontgc, BlackPixel(display, screen));
  444.     XSetForeground(display, fontgc, WhitePixel(display, screen));
  445.     XSetFont(display, fontgc, fixedfont->fid);
  446.  
  447.     /* Determine the width of the string */
  448.  
  449.     w = XTextWidth(fixedfont, str, strlen(str));
  450.     if (w > wwidth)
  451.         w = wwidth;
  452.  
  453.     /* And draw the string */
  454.  
  455.     XDrawImageString(display, window, fontgc, (wwidth-w)/2,
  456.              wheight/2, str, strlen(str));
  457.  
  458.     /* Free everything and show the text */
  459.  
  460.     XFreeGC(display, fontgc);
  461.     XFreeFont(display, fixedfont);
  462.     XFlush(display);
  463.     }
  464. }
  465.  
  466.  
  467. main(argc, argv)
  468. char **argv;
  469. {
  470.     int fd;            /* For the main file descriptor */
  471.     struct fli_header header;    /* To hold the main header */
  472.     unsigned char *data;    /* Always has the current image data */
  473.     int repeatcount;        /* How many times to loop */
  474.     unsigned char notfirst;    /* Is this not the first time through? */
  475.     char *fname;        /* Pointer to filename */
  476.  
  477.     /* X stuff begins here */
  478.  
  479.     XSizeHints hints;        /* Hints for window mapping */
  480.     Visual *visual;
  481.     int xloc, yloc;
  482.  
  483.  
  484.     fdelay = -1;
  485.     repeatcount = 10;
  486.  
  487.     while (--argc && argv[1][0] == '-')
  488.     {
  489.     argv++;
  490.     switch (argv[0][1]) {
  491.     case 'r':
  492.         repeatcount = atol(&(argv[0][2]));
  493.         break;
  494.     case 'd':
  495.         fdelay = atol(&(argv[0][2]));
  496.         break;
  497.     case 'n':
  498.         flag_noint = 1;
  499.         break;
  500.     case 'i':
  501.         flag_img = 1;
  502.         break;
  503.       case 'v':
  504.         verbose = 1;
  505.         break;
  506.     default:
  507.         usage();
  508.     }
  509.  
  510.     }
  511.  
  512.     if (argc != 1)
  513.     usage();
  514.  
  515.     fname = argv[1];
  516.     fd = open(fname, 0);
  517.     if (fd < 0)
  518.     {
  519.     (void) fprintf(stderr, "Error opening %s.\n", fname);
  520.     perror("xflick");
  521.     exit(1);
  522.     }
  523.  
  524.     /* Read the main FLI header */
  525.  
  526.     read_flihead(fd, &header);
  527.  
  528.     if ((header.fhd_magic & 0x0000ffff) != FLI_MAGIC)
  529.     {
  530.     (void) fprintf(stderr, "%s, not a .fli file.\n", fname);
  531.     exit(0);
  532.     }
  533.  
  534.     /* Get the width and height */
  535.  
  536.     wwidth = header.fhd_width;
  537.     wheight = header.fhd_height;
  538.     data = (unsigned char *)malloc(wwidth * wheight);
  539.  
  540.     /* The speed is stored in 1/70 seconds, convert to usecs */
  541.  
  542.     if (fdelay<0)
  543.     fdelay = header.fhd_speed;
  544.     convert_fdelay();
  545.  
  546.     display = XOpenDisplay(NULL);
  547.     if (display == NULL)
  548.     xferror("Cannot open display.");
  549.  
  550.     /* Create a wwidth x wheight window to show the flick */
  551.  
  552.     screen = DefaultScreen(display);
  553.     visual = DefaultVisual(display, screen);
  554.     rootw = RootWindow(display, screen);
  555.  
  556.     if (DisplayCells(display, screen) < 256)
  557.     xferror("You do not have enough colors to run xflick.");
  558.  
  559.     xloc = (DisplayWidth(display, screen) - wwidth) / 2;
  560.     yloc = (DisplayHeight(display, screen) - wheight) / 2;
  561.  
  562.     window = XCreateSimpleWindow(display, rootw, xloc, yloc, wwidth, wheight,
  563.         CopyFromParent, CopyFromParent, BlackPixel(display, screen));
  564.  
  565.     /* Set size hints to disable resizing */
  566.  
  567.     hints.flags = (PSize | PMinSize | PMaxSize);
  568.     hints.min_width = hints.max_width = hints.width = wwidth;
  569.     hints.min_height = hints.max_height = hints.height = wheight;
  570.  
  571.     /* Set window and icon name, size hints and other properties */
  572.  
  573.     XSetStandardProperties(display, window, fname, fname, None,
  574.                argv, argc, &hints);
  575.  
  576.     gc = DefaultGC(display, screen);
  577.  
  578.     /* Create a GC with a foreground pixel value of 0 for FLI_BLACK */
  579.  
  580.     blackgc = XCreateGC(display, rootw, 0, NULL);
  581.     XCopyGC(display, gc, -1, blackgc);
  582.     XSetForeground(display, blackgc, 0);
  583.  
  584.     /* Create a colormap and allocate all colors */
  585.  
  586.     cmap = XCreateColormap(display, rootw, visual, AllocAll);
  587.  
  588.     /* Catch Exposure events and KeyPress events */
  589.  
  590.     XSelectInput(display, window, ExposureMask | KeyPressMask);
  591.  
  592.     /* Now map our little window */
  593.     XMapWindow(display, window);
  594.  
  595.     /* We wait for an exposure event, since any output to the window is
  596.        lost if the window is not yet visible */
  597.  
  598.     do
  599.     XNextEvent(display, &event);
  600.     while (event.type != Expose);
  601.  
  602.     /* Now we are no longer interested in Exposure events */
  603.  
  604.     XSelectInput(display, window, KeyPressMask);
  605.  
  606.     /* Create the XImage to hold the current frame */
  607.     img = XCreateImage(display, visual, 8, ZPixmap, 0,
  608.                data, wwidth, wheight, 8, wwidth);
  609.  
  610.  
  611.     notfirst = 0;
  612.  
  613.     /* Either interpret the file while displaying it */
  614.  
  615.     if (flag_noint)
  616.     {
  617.     while (repeatcount--) {
  618.         interpret_fli(fd, &header, data, notfirst, func_disp);
  619.         notfirst = 1;
  620.     }
  621.     }
  622.  
  623.     /* Or interpret everything first and display it afterwards */
  624.  
  625.     else
  626.  
  627.     {
  628.     text_center("Please wait while loading the animation");
  629.  
  630.     /* Interpret it and store the results */
  631.  
  632.     disp_cur = &disp_root;
  633.     interpret_fli(fd, &header, data, 0, func_interp);
  634.  
  635.     /* Now display the results */
  636.  
  637.     while (repeatcount--)
  638.     {
  639.         disp_cur = &disp_root;
  640.         while (disp_cur->disp_next)
  641.         {
  642.         disp_cur = disp_cur->disp_next;
  643.  
  644.         /* Only display the first frame once */
  645.  
  646.         if (disp_cur->disp_frame || !notfirst)
  647.             display_interp(disp_cur);
  648.         }
  649.         notfirst = 1;
  650.     }
  651.     }
  652.  
  653.     return 0;
  654. }
  655.  
  656.